﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;

namespace FAST
{

    /// <summary>
    /// Enumeration declared for synchronization actions to be performed.
    /// Will be used as status for files or folders.
    /// </summary>
    public enum SyncActions
    {
        DEFAULT, COPY_LEFT, COPY_RIGHT, DELETE
    }

    /// <summary>
    /// Enumeration declared to classify the type of status for removable drive(s).
    /// </summary>
    public enum DriveStatus
    {
        LEFT_REMOV, RIGHT_REMOV, BOTH_REMOV, BOTH_LOCAL
    }

    /// <summary>
    /// To manipulate the changees files and folders. 
    /// </summary>
    public class UpdateReconcilation
    {
        private MessageLog msgLog;
        private List<int[]> leftConList;
        private List<int[]> rightConList;
        private FileVersioning fileVer;
        private FileVersioning fileVerRemov;
        private FileVersioning fileVerRemov1;
        private DriveStatus leftRightDrives;

        //delegate and event to log operations and exceptions.
        //public delegate void MsgLogHandler(string message);
        //public event MsgLogHandler MsgLogEvent;
        
        //to print timestamp for log.
        private DateTime currentTimeStamp;
        private const string DATE_PATT = @"M/d/yyyy hh:mm:ss.fff tt";

        /// <summary>
        /// An instance of UpdateReconcilation object.
        /// </summary>
        /// <exception cref="None"></exception>
        public UpdateReconcilation()
        {
            this.leftConList = new List<int[]>();
            this.rightConList = new List<int[]>();
            this.msgLog = new MessageLog();
        }


        /// <summary>
        /// Set file status of the left/right list object, version the FileHandler that is going to overwritten, handle any conflicting object and reconcile left/right list object. 
        /// </summary>
        /// <param name="leftList">The left list of files/folders</param>
        /// <param name="rightList">"The right list of files/folders</param>
        /// <param name="leftFoldPath">The left folder path</param>
        /// <param name="rightFoldPath">The right folder path</param>
        /// <exception cref="IndexOutOfRangeException">Accessing or updating of Left/ Right list may incur this exception.</exception>
        public void performReconcilation(List<FilesHandler> leftList, List<FilesHandler> rightList, string leftFoldPath, string rightFoldPath)
        {
            //OnMsgLogEvent("System Operation: Start Sychronization\n");
            //this.leftConList = new List<int[]>();
            //this.rightConList = new List<int[]>();

            this.leftRightDrives = removeableDriveCheck(leftFoldPath, rightFoldPath);

            //Check if conflict exist first - usually second call will enter.
            if (this.leftConList.Count != 0 && this.rightConList.Count != 0)
            {
                updateConflictLog(leftList, rightList, leftFoldPath, rightFoldPath);
                versionConflicts(leftList, rightList);
                reconcileFile(leftList, rightList, leftFoldPath, rightFoldPath);
            }
            else //normal sync
            {
                processStatusConflictVersion(leftList, rightList, leftFoldPath, rightFoldPath);
                //processConflicts(leftList, rightList, leftFoldPath, rightFoldPath);
                reconcileFile(leftList, rightList, leftFoldPath, rightFoldPath);
            }

            
            //OnMsgLogEvent("System Operation: End Sychronization\n\n");

        }

        private DriveStatus removeableDriveCheck(string driveLeftPath, string driveRightPath)
        {
            DriveInfo leftDrive = new DriveInfo(driveLeftPath);
            DriveInfo rightDrive = new DriveInfo(driveRightPath);

            if (!(leftDrive.DriveType == DriveType.Removable && rightDrive.DriveType == DriveType.Removable))
            {
                if (leftDrive.DriveType == DriveType.Removable)
                {
                    this.fileVer = new FileVersioning();
                    this.fileVerRemov = new FileVersioning(driveLeftPath);
                    return DriveStatus.LEFT_REMOV;
                }
                else if (rightDrive.DriveType == DriveType.Removable)
                {
                    this.fileVer = new FileVersioning();
                    this.fileVerRemov = new FileVersioning(driveRightPath);
                    return DriveStatus.RIGHT_REMOV;
                }
                else
                {
                    this.fileVer = new FileVersioning();
                    return DriveStatus.BOTH_LOCAL;
                }
            }
            else
            {
                this.fileVerRemov = new FileVersioning(driveLeftPath);
                this.fileVerRemov1 = new FileVersioning(driveRightPath);
                return DriveStatus.BOTH_REMOV;
            }
        }

        private void processStatusConflictVersion(List<FilesHandler> leftList, List<FilesHandler> rightList, string leftFoldPath, string rightFoldPath)
        {
            updateListOperations(leftList, rightList, rightFoldPath, true);
            updateListOperations(rightList, leftList, leftFoldPath, false);
        }

        private void processConflicts(List<FilesHandler> leftList, List<FilesHandler> rightList, string leftFoldPath, string rightFoldPath)
        {
            if (this.leftConList.Count != 0 && this.rightConList.Count != 0)
            {
                resolveConflict(leftList, rightList);
                updateConflictLog(leftList, rightList, leftFoldPath, rightFoldPath);

                versionConflicts(leftList, rightList);
            }
        }


        /// <summary>
        /// Compare left/right list object dirty bit and set their file status accordingly.
        /// </summary>
        /// <param name="list1"></param>
        /// <param name="list2"></param>
        /// <param name="leftConList">The left conflicts list</param>
        /// <param name="rightConList">The right conflicts list</param>
        /// <param name="desFoldPath">The destination path</param>
        /// <param name="isLeftList"></param>
        /// <exception cref="IndexOutOfRangeException">Accessing or updating of Left/ Right list may incur this exception.</exception>
        public void updateListOperations(List<FilesHandler> list1, List<FilesHandler> list2, string desFoldPath, bool isLeftList)
        {
            //FileVersioning fileVer = new FileVersioning();

            int count = 0;
            while (count < list1.Count)
            {
                if (!list1[count].isTypeFile())
                {
                    FolderHandler foldHandler = (FolderHandler)list1[count];

                    handleFolderOperations(foldHandler, list2, desFoldPath, isLeftList);
                }
                else if (list1[count].isTypeFile() )
                {
                    handleFileOperations(list1, list2, isLeftList, count);
                }
                count++;
            }
        }

        private void handleFileOperations(List<FilesHandler> list1, List<FilesHandler> list2, bool isLeftList, int count)
        {
            FileHandler currentFile = (FileHandler)list1[count];
            string filePathToCompare = currentFile.getSubFilePath();

            FileHandler newFile = new FileHandler(filePathToCompare);
            int list2Index = list2.IndexOf(newFile);

            if (currentFile.isDirty())
            {
                handlesDirtyFile(list2, isLeftList, count, currentFile, list2Index);
            }
            else
            {
                handlesNotDirtyFile(currentFile, list1, list2Index, count, isLeftList);
            }
        }

        private void handlesDirtyFile(List<FilesHandler> list2, bool isLeftList, int count, FileHandler currentFile, int list2Index)
        {
            if (list2Index == -1) //this implies file does not exits in another list.
            {
                bool conflictExists = conflictsCheck(currentFile, list2Index, count, false, isLeftList);

                if (!conflictExists)
                {
                    //Set status for file addition.
                    if (isLeftList == true)
                    {
                        currentFile.setFileStatus((int)SyncActions.COPY_RIGHT);
                    }
                    else
                    {
                        currentFile.setFileStatus((int)SyncActions.COPY_LEFT);
                    }

                    //set version bit for the file to be replaced. Dun think will ever go in here.
                    /*if (list2Index != -1)
                    {
                        this.fileVer.createVersion((FileHandler)list2[list2Index]);
                    }*/
                }
            }
            else
            {
                //if (((FileHandler)list2[list2.IndexOf(newFile)]).isDirty() == true || currentFile.isTimeConflictCheck())
                //both side modified
                if (((FileHandler)list2[list2Index]).isDirty())
                {
                    conflictsCheck(currentFile, list2Index, count, true, isLeftList);
                }
                else
                {
                    //Set status when one of the file is modified only.
                    if (isLeftList == true)
                    {
                        currentFile.setFileStatus((int)SyncActions.COPY_RIGHT);
                        versionOneFile((FileHandler)list2[list2Index], this.leftRightDrives, false);
                    }
                    else
                    {
                        currentFile.setFileStatus((int)SyncActions.COPY_LEFT);
                        versionOneFile((FileHandler)list2[list2Index], this.leftRightDrives, true);
                    }

                    //preparing to version the corresponding file being replaced.
                    //versionOneFile((FileHandler)list2[list2Index], this.leftRightDrives);
                    // if (list2Index != -1)
                    // {
                    //this.fileVer.createVersion((FileHandler)list2[list2Index]);
                    //}
                }
            }
        }


        private void handlesNotDirtyFile(FileHandler currentFile, List<FilesHandler> list1, int list2Index, int count, bool isLeftList)
        {
            //Sets status for file deletion.
            if (list2Index == -1)
            {
                currentFile.setFileStatus((int)SyncActions.DELETE);
                //preparing to version itself.
                //this.fileVer.createVersion((FileHandler)list1[count]);
                if (isLeftList)
                {
                    versionOneFile((FileHandler)list1[count], this.leftRightDrives, true);
                }
                else
                {
                    versionOneFile((FileHandler)list1[count], this.leftRightDrives, false);
                }
            }
            else
            {
                //Both file not modified, status set to default
                currentFile.setFileStatus((int)SyncActions.DEFAULT);
            }
        }

        private void versionOneFile(FileHandler fh, DriveStatus pathsDriveStatus, bool isVersionLeftFile)
        {
            switch (pathsDriveStatus)
            {
                case DriveStatus.BOTH_LOCAL:
                    this.fileVer.createVersion(fh);
                    break;
                case DriveStatus.LEFT_REMOV:
                    if (isVersionLeftFile)
                    {
                        //if left file is to be versioned, new version object will be created at removable drive and local drive.
                        this.fileVerRemov.createVersion(fh);
                        this.fileVer.createVersion(fh);
                    }
                    else
                    {
                        //if right file is to be versioned, since it is not a file in removable drive, new version object will created to local drive only.
                        this.fileVer.createVersion(fh);
                    }
                    break;
                case DriveStatus.RIGHT_REMOV:
                    if (!isVersionLeftFile)
                    {
                        //if right file is to be versioned, new version object will be added to the ver
                        this.fileVerRemov.createVersion(fh);
                        this.fileVer.createVersion(fh);
                    }
                    else
                    {
                        this.fileVer.createVersion(fh);
                    }
                    break;
                case DriveStatus.BOTH_REMOV:
                    //NEED to ask...If both path are removable drives, each file will be versioned separately to their respective location.
                    if (isVersionLeftFile)
                    {
                        this.fileVerRemov.createVersion(fh);
                    }
                    else
                    {
                        this.fileVerRemov1.createVersion(fh);
                    }
                    break;
            }
        }

        
        private bool conflictsCheck(FileHandler currentFile, int list2Index, int count, bool existInList2, bool isLeftList)
        {
            bool conflictExist = false; 

            if (existInList2) // current file dirty and corresponding file dirty
            {   
                if (isLeftList == true)
                {
                    // Set status for Conflict type 2 where both files are modified. 
                    int[] conLObj = { count, (int)ConflictTypes.L_R_MOD };
                    //int[] conRObj = { list2.IndexOf(newFile), (int)ConflictTypes.L_R_MOD };
                    int[] conRObj = { list2Index, (int)ConflictTypes.L_R_MOD };

                    // Set status for Conflict type 3 time tampering on both side
                    if (currentFile.isTimeConflictCheck())
                    {
                        conLObj[1] = (int)ConflictTypes.TIME_CON;
                        conRObj[1] = (int)ConflictTypes.TIME_CON;
                    }

                    this.leftConList.Add(conLObj);
                    this.rightConList.Add(conRObj);

                    currentFile.setFileStatus((int)SyncActions.DEFAULT);
                }
                else
                {
                    currentFile.setFileStatus((int)SyncActions.DEFAULT);
                }
                conflictExist = true; 
            }
            else
            {
                if (currentFile.isTimeConflictCheck())
                {
                    //Set status for time conflict, where one file is modified.
                    if (isLeftList == true)
                    {
                        int[] conLObj = { count, (int)ConflictTypes.TIME_CON };
                        this.leftConList.Add(conLObj);
                        //Please check the status again!
                        int[] conRObj = { list2Index, (int)SyncActions.DEFAULT };

                        this.rightConList.Add(conRObj);
                       
                    }
                    else
                    {
                        int[] conRObj = { count, (int)ConflictTypes.TIME_CON };
                        rightConList.Add(conRObj);
                        int[] conLObj = { list2Index, (int)SyncActions.DEFAULT };

                        this.leftConList.Add(conLObj);
                  
                    }
                    conflictExist = true;
                }
                else if (currentFile.isInOSCheck())
                {
                    //Set status for conflict type 1 where one files is modified and one file is deleted. 
                    if (isLeftList == true)
                    {
                        int[] conLObj = { count, (int)ConflictTypes.L_MOD_R_DEL };

                        this.leftConList.Add(conLObj);
                        int[] conRObj = { -1, (int)ConflictTypes.L_MOD_R_DEL };

                        this.rightConList.Add(conRObj);
                    }
                    else
                    {
                        int[] conRObj = { count, (int)ConflictTypes.R_MOD_L_DEL };

                        this.rightConList.Add(conRObj);
                        int[] conLObj = { -1, (int)ConflictTypes.R_MOD_L_DEL };

                        this.leftConList.Add(conLObj);
                        
                    }
                    conflictExist = true;
                }
            }

            return conflictExist;
        }

        private void handleFolderOperations(FolderHandler foldHandler, List<FilesHandler> list2, string desFoldPath, bool isLeftList)
        {
            string foldPathToCompare = desFoldPath + foldHandler.getSubFolderPath();
            FolderHandler newFolder = new FolderHandler(foldPathToCompare);

            if (foldHandler.isDirty())
            {
                //Set status for folder addition.
                if (!list2.Contains((FolderHandler)newFolder))
                {
                    if (isLeftList == true)
                    {
                        foldHandler.setFolderStatus((int)SyncActions.COPY_RIGHT);
                    }
                    else
                    {
                        foldHandler.setFolderStatus((int)SyncActions.COPY_LEFT);
                    }
                }
                //else modified op for folder => do nothing 
            }
            else
            {
                //Set status for folder deletion.
                if (!list2.Contains(newFolder))
                {
                    foldHandler.setFolderStatus((int)SyncActions.DELETE);
                }
                //else do nothing - folders are not modified.
            }
        }

        public void resolveConflict(List<FilesHandler> leftList, List<FilesHandler> rightList)
        {
            ConflictsCore conflict = new ConflictsCore(leftList, rightList, this.leftConList, this.rightConList /*, leftFoldPath, rightFoldPath*/);

        }


        /// <summary>
        /// Create versions of FileHandler after user decides an action.
        /// </summary>
        /// <param name="leftList">The left list of files/folders</param>
        /// <param name="rightList">The right list of files/folders</param>
        /// <param name="leftConList">The left conflicts list</param>
        /// <param name="rightConList">The right conflicts list</param>
        /// <exception cref="IndexOutOfRangeException">Accessing or updating of Left/ Right list may incur this exception.</exception>
        public void versionConflicts(List<FilesHandler> leftList, List<FilesHandler> rightList)
        {
            int[] conLObj;
            int[] conRObj;
            //FileVersioning versioning = new FileVersioning();

            //here
            for (int i = 0; i < this.leftConList.Count; i++)
            {
                conLObj = this.leftConList[i];
                conRObj = this.rightConList[i];

                if (conLObj[0] != -1)
                {
                    if (((FileHandler)leftList[conLObj[0]]).getFileStatus() == (int)SyncActions.COPY_RIGHT)
                    {
                        if (conRObj[0] != -1) //if right file does not exist, don't version!
                        {
                            //versioning.createVersion((FileHandler)rightList[conRObj[0]]);
                            versionOneFile((FileHandler)rightList[conRObj[0]], this.leftRightDrives, false);
                        }
                    }
                    else if (((FileHandler)leftList[conLObj[0]]).getFileStatus() == (int)SyncActions.DELETE)
                    {
                        //versioning.createVersion((FileHandler)leftList[conLObj[0]]);
                        versionOneFile((FileHandler)leftList[conLObj[0]], this.leftRightDrives, true);
                    }
                }

                if (conRObj[0] != -1)
                {
                    if (((FileHandler)rightList[conRObj[0]]).getFileStatus() == (int)SyncActions.COPY_LEFT)
                    {
                        if (conLObj[0] != -1)
                        {
                            //versioning.createVersion((FileHandler)leftList[conLObj[0]]);
                            versionOneFile((FileHandler)leftList[conLObj[0]], this.leftRightDrives, true);
                        }
                    }
                    else if (((FileHandler)rightList[conRObj[0]]).getFileStatus() == (int)SyncActions.DELETE)
                    {
                        //versioning.createVersion((FileHandler)rightList[conRObj[0]]);
                        versionOneFile((FileHandler)rightList[conRObj[0]], this.leftRightDrives, false);
                    }
                }
            }
        }

        public void reconcileFile(List<FilesHandler> leftList, List<FilesHandler> rightList, string leftFoldPath, string rightFoldPath)
        {

            //process from LeftList 
            processLROperations(leftList, rightList, rightFoldPath);

            //process from RightList 
            processLROperations(rightList, leftList, leftFoldPath);

        }

        public void copyFile(string srcFilePath, string desFilePath)
        {
            try
            {
                if (File.Exists(desFilePath))
                {
                    //logic operator 
                    if (((File.GetAttributes(desFilePath) & FileAttributes.Hidden) == FileAttributes.Hidden) ||
                        ((File.GetAttributes(desFilePath) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly))
                    {
                        //Make the file unhidden in order to overwrites it.
                        File.SetAttributes(desFilePath, FileAttributes.Normal);
                    }
                }
               

                File.Copy(srcFilePath, desFilePath, true);
                
                currentTimeStamp = DateTime.Now;
                msgLog.appendAllMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] File Copied from \"" + srcFilePath + "\" to \"" + desFilePath + "\" successfully.\n");
                msgLog.appendChangesMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] File Copied from \"" + srcFilePath + "\" to \"" + desFilePath + "\" successfully.\n");
                
                /*currentTimeStamp = DateTime.Now;
                OnMsgLogEvent("[" + currentTimeStamp.ToString(DATE_PATT) + "]\tFile Copied from \"" + srcFilePath + "\" to \"" + desFilePath + "\" successfully.\n");*/
            }
            catch (Exception)
            {
                currentTimeStamp = DateTime.Now;
                msgLog.appendAllMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] Exception: File failed to copy from \"" + srcFilePath + "\" to \"" + desFilePath + "\". \n");
                msgLog.appendErrorMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] Exception: File failed to copy from \"" + srcFilePath + "\" to \"" + desFilePath + "\". \n");
               /* OnMsgLogEvent("[" + currentTimeStamp.ToString(DATE_PATT) + "]\tFile failed to copy from \"" + srcFilePath + "\" to \"" + desFilePath + "\". \n  Exception Message: " + ex.Message + ".\n");*/
            }
        }

        public void createNewDirectory(string fullFoldPath)
        {
            try
            {
                Directory.CreateDirectory(fullFoldPath);

                currentTimeStamp = DateTime.Now;
                msgLog.appendAllMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] New Folder created at \"" + fullFoldPath + "\" successfully.\n");
                msgLog.appendChangesMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] New Folder created at \"" + fullFoldPath + "\" successfully.\n");
                /*OnMsgLogEvent("[" + currentTimeStamp.ToString(DATE_PATT) + "]\tNew Folder created at \"" + fullFoldPath + "\" successfully.\n");*/
            }
            catch (Exception)
            {
                currentTimeStamp = DateTime.Now;
                msgLog.appendAllMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] Exception: New Folder failed to create at \"" + fullFoldPath + "\". \n");
                msgLog.appendErrorMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] New Folder failed to create at \"" + fullFoldPath + "\". \n");
                /*OnMsgLogEvent("[" + currentTimeStamp.ToString(DATE_PATT) + "]\tNew Folder failed to create at \"" + fullFoldPath + "\". \nException Message: " + ex.Message + ".\n");*/
            }

        }

        public void deleteDirectory(string fullFoldPath)
        {
            try
            {
                if (Directory.Exists(fullFoldPath))
                {
                    Directory.Delete(fullFoldPath, true);
                }

                //not place inside the if so as to log the cascate delete - the list is not modified. => will attempt to delete deleted files.
                currentTimeStamp = DateTime.Now;
                msgLog.appendAllMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] Folder at \"" + fullFoldPath + "\" is deleted successfully.\n");
                msgLog.appendChangesMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] Folder at \"" + fullFoldPath + "\" is deleted successfully.\n");
                
                /*OnMsgLogEvent("[" + currentTimeStamp.ToString(DATE_PATT) + "]\tFolder at \"" + fullFoldPath + "\" is deleted successfully.\n");*/
            }
            catch (Exception)
            {
                currentTimeStamp = DateTime.Now;
                msgLog.appendAllMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] Exception: Folder failed to delete at \"" + fullFoldPath + "\".\n");
                msgLog.appendErrorMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] Folder failed to delete at \"" + fullFoldPath + "\".\n");
               
                /*OnMsgLogEvent("[" + currentTimeStamp.ToString(DATE_PATT) + "]\tFolder failed to delete at \"" + fullFoldPath + "\".\nException Message: " + ex.Message + ".\n");*/
            }
        }

        public void deleteFile(string fullFilePath)
        {
            try
            {
                if (File.Exists(fullFilePath))
                {
                    File.Delete(fullFilePath);
                }

                currentTimeStamp = DateTime.Now;
                msgLog.appendAllMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] File from \"" + fullFilePath + "\" is deleted successfully.\n");
                msgLog.appendChangesMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] File from \"" + fullFilePath + "\" is deleted successfully.\n");
                /*OnMsgLogEvent("[" + currentTimeStamp.ToString(DATE_PATT) + "]\tFile from \"" + fullFilePath + "\" is deleted successfully.\n");*/
            }
            catch (Exception)
            {
                currentTimeStamp = DateTime.Now;
                msgLog.appendAllMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] Exception: File failed to delete at \"" + fullFilePath + "\".\n");
                msgLog.appendErrorMsg("[" + currentTimeStamp.ToString(DATE_PATT) + "] File failed to delete at \"" + fullFilePath + "\".\n");
                /*OnMsgLogEvent("[" + currentTimeStamp.ToString(DATE_PATT) + "]\tFile failed to delete at \"" + fullFilePath + "\".\nException Message: " + ex.Message + ".\n");*/
            }
        }

        //List update for folder creation.
        public void updateListFoldChanges(string tempFullPath, FolderHandler currentFold, List<FilesHandler> list2)
        {
            DirectoryInfo newDi = new DirectoryInfo(tempFullPath);
            FolderHandler newFolder = new FolderHandler(tempFullPath, currentFold.getSubFolderPath(), newDi, false, 0);

            FolderHandler parent = new FolderHandler(newDi.Parent.FullName);
            int index = list2.IndexOf(parent);

            int noOfFiles = 0;
            noOfFiles = totalNoOfFilesInFold(newDi.Parent.FullName, tempFullPath);

            if (index != -1)
            {
                //exclude the folder itself
                list2.Insert(index + noOfFiles + 1, newFolder);
            }
            else
            {
                if (index + noOfFiles == -1)
                {
                    list2.Insert(0, newFolder);
                }
                else
                {
                    list2.Insert(noOfFiles, newFolder);
                }
            }

        }

        //overload for folder delete update.
        public void updateListFoldChanges(FolderHandler currentDelFold, List<FilesHandler> list1, int currentIndex)
        {
            //Update list
            DirectoryInfo foldHandlerDi = new DirectoryInfo(currentDelFold.getFullFolderPath());

            int noOfFiles = 0;
            noOfFiles = totalNoOfFilesInFold(currentDelFold.getFullFolderPath(), currentDelFold.getFullFolderPath()/*, noOfFiles*/);
            noOfFiles++;//include itself => + 1

            list1.RemoveRange(currentIndex, noOfFiles);
        }

        public void updateListFileChanges(string tempFullPath, string tempFilePath, FileHandler currentFile, List<FilesHandler> list2, bool isAddOp)
        {
            //Update list1 - revert bit.
            currentFile.setDirtyBit(false);
            //Update list2 - add op
            if (isAddOp)
            {
                FileHandler newFile = new FileHandler(tempFullPath, currentFile.getSubFilePath(), new FileInfo(tempFullPath), false, 0);
                newFile.setMd5HashCode(currentFile.getMd5HashCode());

                //rearrange the list elements according to their parent directory.
                string parentFoldPath = tempFullPath.Substring(0, tempFullPath.LastIndexOf('\\'));
                FolderHandler parent = new FolderHandler(parentFoldPath);
                int index = list2.IndexOf(parent);


                list2.Insert(index + 1, newFile);
            }
            else
            {
                //Update on Copy L to R or R to L.
                //Update des file's properties. => handling conflicts issues.
                //Where there exist a file in the list 2.
                FilesHandler compareFile = new FileHandler(tempFilePath);
                int desIndex = list2.IndexOf(compareFile);

                FileHandler newUpdatedFile = new FileHandler(tempFullPath, currentFile.getSubFilePath(), new FileInfo(tempFullPath), false, 0);
                newUpdatedFile.setMd5HashCode(currentFile.getMd5HashCode());
                newUpdatedFile.setVersioningIdx(((FileHandler)list2[desIndex]).getVersioningIdx());
                list2[desIndex] = newUpdatedFile;
                
            }
        }


        /// <summary>
        /// Check file or folder status and perform file operations to the physical files and folders location. Left/right list will be updated according to the final state of both Left/right location.
        /// </summary>
        /// <param name="list1"></param>
        /// <param name="list2"></param>
        /// <param name="desFoldPath">The destination folder path</param>
        /// <exception cref="IndexOutOfRangeException">Accessing or updating of Left/ Right list may incur this exception.</exception>
        public void processLROperations(List<FilesHandler> list1, List<FilesHandler> list2, string desFoldPath)
        {
            //New a version class
            //FileVersioning versioning = new FileVersioning();

            //Processleft & right list => check each status for file and folder status(currently dun wan)
            int count = 0; //skip root folder
            while (count < list1.Count)
            {
                if (!list1[count].isTypeFile())
                {
                    //Handler Folders
                    FolderHandler currentFold = (FolderHandler)list1[count];

                    switch ((SyncActions)currentFold.getFolderStatus())
                    {
                        case SyncActions.COPY_LEFT:
                        case SyncActions.COPY_RIGHT:
                            string tempFoldPath = desFoldPath + currentFold.getSubFolderPath();
                            createNewDirectory(tempFoldPath);
                            updateListFoldChanges(tempFoldPath, currentFold, list2);

                            break;

                        case SyncActions.DELETE:
                            /**Folder delete -Propagate delete
                             * On first entry, Folder will be physically deleted.
                             * But on virtual list(Left/right), will not be deleted yet.
                            **/
                            // folderDelete = true;
                            updateListFoldChanges(currentFold, list1, count);
                            deleteDirectory(currentFold.getFullFolderPath());
                            continue;
                        //break;
                    }
                }
                else
                {
                    //Handle Files.
                    FileHandler currentFile = (FileHandler)list1[count];
                    switch ((SyncActions)currentFile.getFileStatus())
                    {
                        case SyncActions.COPY_LEFT:
                        case SyncActions.COPY_RIGHT:

                            //check if this operation is add new or modify.
                            bool isAddOp = false;
                            if (!File.Exists(desFoldPath + currentFile.getSubFilePath()))
                            {
                                isAddOp = true;
                            }

                            string tempFilePath = desFoldPath + currentFile.getSubFilePath();
                            copyFile(currentFile.getFullFilePath(), tempFilePath);
         

                            updateListFileChanges(tempFilePath, currentFile.getSubFilePath(), currentFile, list2, isAddOp);
                            break;

                        case SyncActions.DELETE:
                            deleteFile(currentFile.getFullFilePath());

                            //Update List1 - delete load
                            list1.RemoveAt(count);
                            continue;
                        //break;
                    }
                }
                count++;
            }
        }

        public void updateConflictLog(List<FilesHandler> leftList, List<FilesHandler> rightList, string lroot, string rRoot)
        {
            //OnMsgLogEvent("\nConflict(s) Encountered:\n");

            string tempMsg = "";
            int[] conLDetails = null;
            int[] conRDetails = null;

            for (int i = 0; i < this.leftConList.Count; i++)
            {
                tempMsg = "";
                conLDetails = this.leftConList[i];
                conRDetails = this.rightConList[i];

                switch ((ConflictTypes)conLDetails[1])
                {
                    case ConflictTypes.L_MOD_R_DEL:
                        tempMsg = "[Conflict Type 0] File is modified at \"" + ((FileHandler)leftList[conLDetails[0]]).getFullFilePath() + "\" and the corresponding file is deleted at right location.\n";
                        break;
                    case ConflictTypes.R_MOD_L_DEL:
                        tempMsg = "[Conflict Type 1] File is modified at \"" + ((FileHandler)rightList[conRDetails[0]]).getFullFilePath() + "\" and the corresponding file is deleted at the left location\n";
                        break;
                    case ConflictTypes.L_R_MOD:
                        tempMsg = "[Conflict Type 2] File is modified at both \"" + ((FileHandler)leftList[conLDetails[0]]).getFullFilePath() + "\" and \"" + ((FileHandler)rightList[conRDetails[0]]).getFullFilePath() + "\".\n";
                        break;
                    case ConflictTypes.TIME_CON:
                        if (conLDetails[0] == -1)
                        {
                            tempMsg = "[Conflict Type 4] File's timestamp is modified at \"" + ((FileHandler)leftList[conRDetails[0]]).getFullFilePath() + "\" and the corresponding file is deleted at the left location.\n";
                        }
                        else if (conRDetails[0] == -1)
                        {
                            tempMsg = "[Conflict Type 5] File's timestamp is modified at \"" + ((FileHandler)leftList[conLDetails[0]]).getFullFilePath() + "\" and the corresponding file is deleted at the right location.\n";
                        }
                        else
                        {
                            tempMsg = "[Conflict Type 3] File's timestamp is modified at both \"" + ((FileHandler)leftList[conLDetails[0]]).getFullFilePath() + "\" and \"" + ((FileHandler)rightList[conRDetails[0]]).getFullFilePath() + "\".\n";
                        }
                        break;
                }

                int fileStat = -1;
                if (conLDetails[0] != -1)
                {
                    fileStat = ((FileHandler)leftList[conLDetails[0]]).getFileStatus();
                    if (conRDetails[0] == -1)
                    {
                        //L mod right delete. used back left index

                    }
                    else if (fileStat != ((FileHandler)rightList[conRDetails[0]]).getFileStatus() && ((FileHandler)rightList[conRDetails[0]]).getFileStatus() != (int)SyncActions.DEFAULT)
                    {
                        fileStat = ((FileHandler)rightList[conRDetails[0]]).getFileStatus();
                    }
                }
                else
                {
                    fileStat = ((FileHandler)rightList[conRDetails[0]]).getFileStatus();
                }

                switch ((SyncActions)fileStat)
                {
                    case SyncActions.COPY_LEFT:
                        tempMsg += "[Action Taken] You have chose to copy file from RIGHT location: \"" + ((FileHandler)rightList[conRDetails[0]]).getFullFilePath() + "\" and replaced the file in LEFT location: \"" + lroot + ((FileHandler)rightList[conRDetails[0]]).getSubFilePath() + "\"\n\n";
                        break;
                    case SyncActions.COPY_RIGHT:
                        tempMsg += "[Action Taken] You have chose to copy file from LEFT location: \"" + ((FileHandler)leftList[conLDetails[0]]).getFullFilePath() + "\" and replaced the file in RIGHT location: \"" + rRoot + ((FileHandler)leftList[conLDetails[0]]).getSubFilePath() + "\"\n\n";
                        break;
                    case SyncActions.DELETE:
                        tempMsg += "[Action Taken] You have chose to follow the delete operation of file in one of the two location.\n\n";
                        break;
                    case SyncActions.DEFAULT:
                        tempMsg += "[Action Taken] You have chose not to handle this conflict.\n\n";
                        break;
                }
                msgLog.appendConflictMsg(tempMsg);
                //OnMsgLogEvent(tempMsg + "\n");
            }
        }

        /// <summary>
        /// Generate message log.
        /// </summary>
        /// <returns>Return the MessageLog object created and populated during reconciliation of files and folder.</returns>
        public MessageLog generateMsgLog()
        {
            return this.msgLog;//??????????????????????????????????????
            //return null;
        }

        #region Method used for Message Log event - To be Removed
        /// <summary>
        /// 
        /// </summary>
        /// <param name="message"></param>
       /* protected void OnMsgLogEvent(string message)
        {
            if (MsgLogEvent != null)
            {
                MsgLogEvent(message);
            }

        } */

        #endregion

        //new method to recursively find the no of files inside the parent folder
        public int totalNoOfFilesInFold(string parentPath, string currentFold /*, int totalFiles*/)
        {

            int totalFiles = 0;

            string[] files = Directory.GetFiles(parentPath);

            totalFiles += files.Length;

            foreach (string folder in Directory.GetDirectories(parentPath))
            {
                if (!folder.Equals(currentFold))
                {
                    totalFiles++;
                    totalFiles += totalNoOfFilesInFold(folder, currentFold);
                }
            }
            return totalFiles;
        }

        /****Get method for update reconcilation***/
        public List<int[]> getLeftConList()
        {
            return this.leftConList;
        }
        public List<int[]> getRightConList()
        {
            return this.rightConList;
        }


        
    }

}
